package com.aispeech.imgany.engineSdk;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.aispeech.AIError;
import com.aispeech.AIResult;
import com.aispeech.common.AIConstant;
import com.aispeech.common.JSONResultParser;
import com.aispeech.common.Util;
import com.aispeech.export.engines.AICloudASREngine;
import com.aispeech.export.engines.AILocalTTSEngine;
import com.aispeech.export.engines.AILocalWakeupDnnEngine;
import com.aispeech.export.listeners.AIASRListener;
import com.aispeech.export.listeners.AIAuthListener;
import com.aispeech.export.listeners.AILocalWakeupDnnListener;
import com.aispeech.export.listeners.AITTSListener;
import com.aispeech.speech.AIAuthEngine;

/**
 * 语音引擎控制类
 *
 * @author rain  01.17 2018
 */

public class VoiceEngineManage {

    private static final String TAG = "VoiceEngineManage";
    private static VoiceEngineManage mInstance;

    private AIAuthEngine mAuthEngine;
    private AILocalWakeupDnnEngine mWakeupEngine;
    private AICloudASREngine mAsrEngine;
    private AILocalTTSEngine mTTSEngine;
//    private AICloudTTSEngine mTTSEngine;

    private MyEngineListener myEngineListener;
    private Context mContext;

    private int try_auth_times = 10;//授权重试次数

    private VoiceEngineManage() {
    }

    public static VoiceEngineManage getInstance() {
        Log.d(TAG, "getInstance: ");
        if (null == mInstance) {
            mInstance = new VoiceEngineManage();
        }
        return mInstance;
    }

    public void initAllEngine(MyEngineListener listener, Context context) {
        Log.d(TAG, "initAllEngine: ");
        mContext = context;

        myEngineListener = listener;
        mAuthEngine = AIAuthEngine.getInstance();
        try {
            mAuthEngine.init();
            mAuthEngine.setOnAuthListener(new AIAuthListener() {
                @Override
                public void onAuthSuccess() {
                    Log.d(TAG, "onAuthSuccess: ");
                    initTTSEngine();
                    myEngineListener.onInitResult("auth");
                }

                @Override
                public void onAuthFailed(final String result) {
                    Log.d(TAG, "onAuthFailed: result = " + result);
                    try {
                        if (try_auth_times > 0) {
                            try_auth_times--;
                            Thread.sleep(1200);
                            mAuthEngine.doAuth();
                        } else {
                            Log.e(TAG, "onAuthFailed: try all times out ! but not success ! stop try auth !");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            if (mAuthEngine.isAuthed()) {
                initTTSEngine();
                myEngineListener.onInitResult("auth");
            } else {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mAuthEngine.doAuth();
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initWakeupEngine() {
        Log.d(TAG, "initWakeupEngine: ");
        if (null != mWakeupEngine) {
            mWakeupEngine.destroy();
        }
        mWakeupEngine = AILocalWakeupDnnEngine.createInstance(); //创建实例
        mWakeupEngine.setResBin(SampleConstants.WAKEUP_RES_BIN); //非自定义唤醒资源可以不用设置words和thresh，资源已经自带唤醒词
        mWakeupEngine.setWords(SampleConstants.WAKEUP_WORDS);
        mWakeupEngine.setThreshold(SampleConstants.WAKEUP_THREADS);
        mWakeupEngine.init(new AISpeechListenerImpl());
        mWakeupEngine.setStopOnWakeupSuccess(true);//设置当检测到唤醒词后自动停止唤醒引擎
    }

    private void initTTSEngine() {
        Log.d(TAG, "initTTSEngine: ");
        if (mTTSEngine != null) {
            mTTSEngine.destroy();
        }

        mTTSEngine = AILocalTTSEngine.createInstance();//创建实例
        mTTSEngine.setResource(SampleConstants.TTS_MODEL_NAME);
        mTTSEngine.setDictDbName(SampleConstants.TTS_DICT_RES);
        mTTSEngine.init(new AITTSListenerImpl());//初始化合成引擎
        mTTSEngine.setSpeechRate(SampleConstants.SPEECH_RATE);//设置语速
        mTTSEngine.setDeviceId(Util.getIMEI(mContext));

        // 创建云端合成播放器
//        mTTSEngine = AICloudTTSEngine.createInstance();
////        mTTSEngine.setRealBack(true);
//        mTTSEngine.init(new AITTSListenerImpl());
//        // 指定默认中文合成
//        mTTSEngine.setLanguage(AIConstant.CN_TTS);
//        mTTSEngine.setRes(SampleConstants.TTS_TYPE);
//        mTTSEngine.setDeviceId(Util.getIMEI(mContext));
    }

    private void initAsrEngine() {
        if (null != mAsrEngine) {
            mAsrEngine.destroy();
        }
        mAsrEngine = AICloudASREngine.createInstance();
        mAsrEngine.setVadResource(SampleConstants.VAD_RES);
        mAsrEngine.setHttpTransferTimeout(10);
        mAsrEngine.setPauseTime(900);
        mAsrEngine.setRes("aihome");
        mAsrEngine.setRTMode(AIConstant.RT_MODE_VAD);//实时反馈识别结果
        mAsrEngine.init(new AICloudASRListenerImpl());
        mAsrEngine.setNoSpeechTimeOut(0);
    }

    public void destroyEngine() {
        Log.d(TAG, "destroyEngine: ");
        if (null != mAsrEngine) {
            mAsrEngine.destroy();
        }
        if (null != mWakeupEngine) {
            mWakeupEngine.destroy();
        }
        if (null != mTTSEngine) {
            mTTSEngine.destroy();
        }
    }


    /**
     * 播报文本内容
     *
     * @param text 需要播报的内容
     */
    public void playTTS(String text) {
        Log.d(TAG, "playTTS with: text = " + text + "");
        try {
            mTTSEngine.speak(text, "1024");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void startWakeup() {
        Log.d(TAG, "startWakeup: ");
        if (null != mWakeupEngine) {
            mWakeupEngine.start();
        }
    }

    public void stopWakeup() {
        Log.d(TAG, "stopWakeup: ");
        if (null != mWakeupEngine) {
            mWakeupEngine.stop();
        }
    }

    public void startAsr() {
        Log.d(TAG, "startAsr: ");
        if (null != mAsrEngine) {
            mAsrEngine.start();
        }
    }

    public void stopAsr() {
        Log.d(TAG, "stopAsr: cancel");
        if (null != mAsrEngine) {
            mAsrEngine.cancel();
        }
    }


    private class AITTSListenerImpl implements AITTSListener {

        @Override
        public void onInit(int status) {
            Log.i(TAG, "初始化完成，返回值：" + status);
            Log.i(TAG, "onInit");
            if (status == AIConstant.OPT_SUCCESS) {
                Log.d(TAG, "初始化成功!");
                initWakeupEngine();
                myEngineListener.onInitResult("tts");
            } else {
                Log.d(TAG, "初始化失败!" + status);
                myEngineListener.onInitResult("error");
            }
        }

        @Override
        public void onProgress(int currentTime, int totalTime, boolean isRefTextTTSFinished) {
//            Log.d(TAG, "当前:" + currentTime + "ms, 总计:" + totalTime + "ms, 可信度:" + isRefTextTTSFinished);
        }


        @Override
        public void onError(String utteranceId, AIError error) {

            Log.d(TAG, "onError with: utteranceId = " + utteranceId + ", error = " + error.toString() + "");
        }

        @Override
        public void onReady(String utteranceId) {
            Log.d(TAG, "onReady: tts");
        }

        @Override
        public void onCompletion(String utteranceId) {
            Log.d(TAG, "onCompletion: tts");
        }
    }

    private class AISpeechListenerImpl implements AILocalWakeupDnnListener {

        private String lastWakeupWord = "";

        @Override
        public void onInit(int status) {
            Log.i(TAG, "Init result " + status);
            if (status == AIConstant.OPT_SUCCESS) {
                initAsrEngine();
                myEngineListener.onInitResult("wakeup");
            } else {
                Log.d(TAG, "onInit: wakeup init err");
                myEngineListener.onInitResult("error");
            }
        }

        @Override
        public void onError(AIError aiError) {
            Log.d(TAG, "onError with: error = " + aiError.toString() + "");
        }

        @Override
        public void onWakeup(String recordId, double confidence, String wakeupWord) {
            Log.d(TAG, "onWakeup with: recordId = " + recordId + ", confidence = " + confidence + ", wakeupWord = " + wakeupWord + "");
            lastWakeupWord = wakeupWord;
        }

        @Override
        public void onRmsChanged(float v) {

        }


        @Override
        public void onRecorderReleased() {

        }


        @Override
        public void onReadyForSpeech() {
            Log.d(TAG, "onReadyForSpeech: ");
        }

        @Override
        public void onBufferReceived(byte[] bytes) {

        }

        @Override
        public void onWakeupEngineStopped() {
            Log.d(TAG, "onWakeupEngineStopped");
//            startWakeup();
            myEngineListener.onWakeupResult(lastWakeupWord);
            startWakeup();
        }

    }

    private class AICloudASRListenerImpl implements AIASRListener {

        @Override
        public void onReadyForSpeech() {
            Log.d(TAG, "onReadyForSpeech: ");
            myEngineListener.onVoiceState(VoiceStateType.listening);
        }

        @Override
        public void onBeginningOfSpeech() {
            Log.d(TAG, "onBeginningOfSpeech: ");
        }

        @Override
        public void onEndOfSpeech() {
            Log.d(TAG, "onEndOfSpeech: ");
            myEngineListener.onVoiceState(VoiceStateType.thinking);

        }

        @Override
        public void onRecorderReleased() {

        }

        @Override
        public void onBufferReceived(byte[] bytes) {

        }

        @Override
        public void onNotOneShot() {

        }


        @Override
        public void onRmsChanged(float rmsdB) {

        }

        @Override
        public void onError(AIError error) {
            Log.e(TAG, "error:" + error.toString());
            myEngineListener.onAsrResult("asr_error", true);
            myEngineListener.onVoiceState(VoiceStateType.silence);
            rec = "";
        }

        String rec = "";

        @Override
        public void onResults(AIResult results) {
            Log.d(TAG, "onResults: " + results.getResultObject().toString());
            if (results.getResultType() == AIConstant.AIENGINE_MESSAGE_TYPE_JSON) {
                Log.i(TAG, "result JSON = " + results.getResultObject().toString());
                // 可以使用JSONResultParser来解析识别结果
                JSONResultParser parser = new JSONResultParser(results.getResultObject()
                    .toString());
//                    String recordId = parser.getRecordId();
                String currRec = TextUtils.isEmpty(parser.getRec()) ? "" : parser.getRec();
                String currVar = TextUtils.isEmpty(parser.getVar()) ? "" : parser.getVar();

                Log.d(TAG, "onResults: rec = " + currRec + " var = " + currVar);

                if (!TextUtils.isEmpty(currRec)) {
                    //有时候中间停顿一下 , 但是又没有超过vad的判断值 , 会出现多段rec情况
                    if (!rec.equals(currRec)) {
                        rec = rec + " " + currRec;
                    }
                }

                if (results.isLast()) {
                    myEngineListener.onAsrResult(rec, true);
                    myEngineListener.onVoiceState(VoiceStateType.silence);
                    rec = "";
                } else {
                    myEngineListener.onAsrResult(rec + currVar, false);
                }
            }
        }

        @Override
        public void onInit(int status) {
            Log.i(TAG, "Init result " + status);
            if (status == AIConstant.OPT_SUCCESS) {
                Log.d(TAG, "onInit: 初始化识别引擎成功");
                myEngineListener.onInitResult("asr");
                myEngineListener.onInitResult("success");
            } else {
                Log.d(TAG, "onInit: 初始化识别引擎失败");
                myEngineListener.onInitResult("error");
            }
        }
    }

}
